package com.mlx.permission.row;

import com.mlx.permission.util.JavaBean;
import com.mlx.permission.util.MapBean;
import com.mlx.permission.entity.RowPermission;
import com.mlx.permission.util.PermissionUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @param <P>
 */
public abstract class AbstractRowValidator<P extends RowPermission> implements IRowValidator<P> {


    @Override
    public boolean isHavePermission(Object data, String tableName, String[] foreignKeys) {

        if (data == null){
            return true;
        }

        // 如果是开放实体，返回true
        if (isOpenEntity()){
            return true;
        }

        // 获取数据表行权限
        Map<String, Set<String>> tablePermissionMap = getTablePermissions(tableName, foreignKeys);

        // 行权限为空，返回false
        if (PermissionUtil.isEmpty(tablePermissionMap)){
            return false;
        }

        // 通过数据类型创建javaBean工具类
        JavaBean javaBean = JavaBean.build(data.getClass());

        // 通过表权限与javaBean对象去判断是否拥有权限
        return isHavePermission(data, tablePermissionMap, javaBean);
    }

    public Map<String, Set<String>> getTablePermissions(String tableName, String[] foreignKeys){

        // 创建空的表权限Map
        Map<String, Set<String>> tablePermissionMap = new HashMap<>();

        // 如果表名与外键列表均为空，返回空的表权限
        if (PermissionUtil.isEmpty(tableName) && PermissionUtil.isEmpty(foreignKeys)){
            return tablePermissionMap;
        }

        // 刷新容器
        Map<String, Map<String, Set<String>>> container = getContainer();

        // 将表名对应表权限加入表权限Map
        if (container.containsKey(tableName)){
            tablePermissionMap.putAll(container.get(tableName));
        }

        // 将外键权限加入表权限Map
        if (PermissionUtil.isNotEmpty(foreignKeys)){
            for (String key : foreignKeys){
                if (!PermissionUtil.isForeignKeysFormat(key)){
                    PermissionUtil.throwException("行数据权限foreignKeys外键数组参数元素【%s】为非法格式的字符串", key);
                }
                String[] keyItems = key.split(":");
                if (container.containsKey(keyItems[1]) && container.get(tableName).containsKey(keyItems[2])){
                    tablePermissionMap.put(keyItems[0], container.get(keyItems[1]).get(keyItems[2]));
                }
            }
        }

        // 返回表权限Map
        return tablePermissionMap;
    }

    @Override
    public Map<String, Map<String, Set<String>>> getContainer() {

        // 清空容器
        Map<String, Map<String, Set<String>>> container = new HashMap<>();

        // 获取当前实体所有权限
        Collection<P> permissionCollection = getPermissionCollection();

        // 将权限放入容器
        Map<String, List<P>> permissionCollectionMap = permissionCollection.stream().collect(Collectors.groupingBy(P::getTableName));
        permissionCollectionMap.forEach((tableName, tablePermissions) -> {
            Map<String, Set<String>> tableMap = new HashMap<>();
            Map<String, List<P>> tablePermissionMap = tablePermissions.stream().collect(Collectors.groupingBy(P::getColumnName));
            tablePermissionMap.forEach((columnName, columnPermissions) -> {
                tableMap.put(columnName, columnPermissions.stream().map(P::getPermissionValue).collect(Collectors.toSet()));
            });
            container.put(tableName, tableMap);
        });

        return container;
    }

    public boolean isHavePermission(Object data, Map<String, Set<String>> tablePermissionMap, JavaBean javaBean) {

        // 获取属性列表
        Set<String> columnSet = tablePermissionMap.keySet();

        for (String column : columnSet){

            // 获取column属性值
            Object columnValue = javaBean.get(data, column);

            // 如果column属性值在表权限的对应列权限空间中，返回true
            if (columnValue != null && tablePermissionMap.get(column).contains(columnValue.toString())){
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean isHavePermission(Object data, String tableName, String[] foreignKeys, String getterName, String setterName, String fieldSetMethodName) {

        if (data == null){
            return true;
        }

        if (isOpenEntity()){
            return true;
        }

        Map<String, Set<String>> tablePermissionMap = getTablePermissions(tableName, foreignKeys);

        if (PermissionUtil.isEmpty(tablePermissionMap)){
            return false;
        }

        MapBean mapBean = MapBean.build(data.getClass(), getterName, setterName, fieldSetMethodName);


        return isHavePermission(data, tablePermissionMap, mapBean);
    }

    public boolean isHavePermission(Object data, Map<String, Set<String>> tablePermissionMap, MapBean mapBean) {

        Set<String> columnSet = tablePermissionMap.keySet();

        for (String column : columnSet){
            Object columnValue = mapBean.get(data, column);
            if (columnValue != null && tablePermissionMap.get(column).contains(columnValue.toString())){
                return true;
            }
        }

        return false;
    }

    @Override
    public void rowFilter(Collection<?> dataCollection, String tableName, String[] foreignKeys){

        if (PermissionUtil.isEmpty(dataCollection)){
            return;
        }

        if (isOpenEntity()){
            return;
        }

        Map<String, Set<String>> tablePermissions = getTablePermissions(tableName, foreignKeys);

        if (PermissionUtil.isEmpty(tablePermissions)){
            return;
        }

        Class<?> dataClass = dataCollection.iterator().next().getClass();

        JavaBean javaBean = JavaBean.build(dataClass);

        dataCollection.removeIf(data -> !isHavePermission(data, tablePermissions, javaBean));
    }

    @Override
    public void rowFilter(Collection<?> dataCollection, String tableName, String[] foreignKeys, String getterName, String setterName, String fieldSetMethodName){
        if (PermissionUtil.isEmpty(dataCollection)){
            return;
        }
        if (isOpenEntity()){
            return;
        }

        Map<String, Set<String>> tablePermissions = getTablePermissions(tableName, foreignKeys);

        if (PermissionUtil.isEmpty(tablePermissions)){
            return;
        }

        Object data0 = dataCollection.iterator().next();

        Class<?> dataClass = data0.getClass();

        MapBean mapBean = MapBean.build(dataClass, getterName, setterName, fieldSetMethodName);

        dataCollection.removeIf(data -> !isHavePermission(data, tablePermissions, mapBean));
    }


}
